#include "searchAlgo.h"
#include "judgment/judgment.h"
#include <iostream>
#include <cassert>

/** alpha-beta minmax **/

ABMinMax::ABMinMax(Go * mirrorCore)
{
    this->mirrorCore = mirrorCore;

    myJudgment = new Judgment();

    whos_turn = 0;

    next_Move_Node = 0;

    /*for(int i=0; i<DEPTH+1; i++)
    {
        _path[i] = 0;
    }*/
}
ABMinMax::~ABMinMax()
{
    if(myJudgment != 0) delete myJudgment;
}

//极小极大搜索,alpha-beta剪枝
coordinate ABMinMax::alphaBetaMinMaxSearch()
{
    //相关成员变量赋值及初始化准备工作
    whos_turn = mirrorCore->whos_turn;
    NodesOperator o = NodesOperator();
    nodesOperator = &o;

    //对初始节点进行估值, 估值函数使用moyoCalculateINFLUENCE()
    //pair<int,int> temp_pair = myJudgment->moyoCalculateINFLUENCE(mirrorCore->board);
    //float temp_score = get_score(temp_pair);

    //创建初始节点对象
    Nodes *start_Node = create_Node(mirrorCore->board, 0);

    //进入极大极小搜索
    //alpha初始值小于估值函数可能值的最小值
    //beta初始值大于估值函数可能值的最大值
    float optimal_solution = alpha_beta_max(start_Node, 0, -999, 999);

    //for test
    cout << "optimal_salution = " << optimal_solution << endl;

    coordinate coo;
    coo.first = 0;
    coo.second = 0;

    if(next_Move_Node == 0) {/** 如果无解就意味着最好下法为PASS??? **/}
    else
    {
        coo = find_diff_parent(next_Move_Node);
        assert(coo.first!=0 && coo.second!=0); /** 实际测试中产生error 2/2 **/
    }

    return coo;
}

/** max中对于depth为0条件下的额外操作是必要的 **/
/** min与max中对于保持mirrorCore与进行中的搜索同步也是必要的 **/
float ABMinMax::alpha_beta_max(const Nodes * const cur_Node, const int cur_depth, const float alpha, const float beta)
{
    //如果到了深度限制则返回估值
    if(cur_depth >= DEPTH)
    {
        int cur_board[DIMENSION][DIMENSION];
        cur_Node->getBoard(cur_board); //获得节点对应的棋盘2维数组

        return get_score(myJudgment->moyoCalculateINFLUENCE(cur_board));
    }

    //函数私有变量声明和初始化
    sub_nodes_t unsearchedNodes;
    float a = alpha;
    float b = beta;

    //如果没有到深度限制则扩展该节点的子节点
    expand_subNodes(cur_Node, &unsearchedNodes);

    //while循环在子节点列表没有为空前进行递归或者剪枝
    while(!unsearchedNodes.empty())
    {
        //获取节点列表中的第一个节点
        deque<Nodes*>::iterator iter = unsearchedNodes.begin();

        //在这里进行递归
        float temp_a = alpha_beta_min(*iter, cur_depth+1, a, b);

        /** FIXME: 如果出现2个估值相同的情况, 是保留a , 还是改为temp_a ??? **/

        //这里加入一个特殊的判断和开关
        //用于判断是否之前的一个节点被剪枝而传回大小一样的
        bool on_off = true;
        if(a == temp_a)
        {
            on_off = false; /** 也可能包含没有剪枝而的确是估值相同的情况 **/
        }
        a = (a >= temp_a) ? a : temp_a;

        //剪枝
        if(a > b)
        {
            if(cur_depth!=0)
            {
                mirrorCore->regret();
            }
            return b;
        }
        //如果为DEPTH==0, 则检查子节点估值, 记录DEPTH==1时的最大值节点
        //在这里获得最优的子节点
        if(cur_depth == 0 && a == temp_a && on_off)
        {
            //确认为新的最大值节点, 进行记录
            next_Move_Node = *iter;
        }

        //删除节点列表的第一个节点
        unsearchedNodes.pop_front();
    }

    if(cur_depth!=0)
    {
        mirrorCore->regret();
    }
    return a;
}

float ABMinMax::alpha_beta_min(const Nodes * const cur_Node, const int cur_depth, const float alpha, const float beta)
{
    //如果到了深度限制则返回估值
    if(cur_depth >= DEPTH)
    {
        int cur_board[DIMENSION][DIMENSION];
        cur_Node->getBoard(cur_board); //获得节点对应的棋盘2维数组

        return get_score(myJudgment->moyoCalculateINFLUENCE(cur_board));
    }

    //函数私有变量声明和初始化
    sub_nodes_t unsearchedNodes;
    float a = alpha;
    float b = beta;

    //如果没有到深度限制则扩展该节点的子节点
    expand_subNodes(cur_Node, &unsearchedNodes);

    //while循环在子节点列表没有为空前进行递归或者剪枝
    while(!unsearchedNodes.empty())
    {
        //获取节点列表中的第一个节点
        deque<Nodes*>::iterator iter = unsearchedNodes.begin();

        //在这里进行递归
        float temp_b = alpha_beta_max(*iter, cur_depth+1, a, b);

        /** FIXME: 如果出现2个估值相同的情况, 是保留b , 还是改为temp_b ??? **/
        b = (b <= temp_b) ? b : temp_b;

        //剪枝
        if(a > b)
        {
            mirrorCore->regret();
            return a;
        }
        //删除节点列表中的第一个节点
        unsearchedNodes.pop_front();
    }

    mirrorCore->regret();
    return b;
}

void ABMinMax::expand_subNodes(const Nodes * const cur_Node, sub_nodes_t *ptr_subNodes)
{
    //每次进入下一级递归进入扩展节点函数时
    //都需要更新同步mirrorCore的盘面数据状态
    if((cur_Node->getParent())!=0) //addtional check avoid null pointer
                                   //here only the start_Node has a null parent pointer
    {
        coordinate coo = find_diff_parent(cur_Node);
        mirrorCore->doit(coo.first, coo.second);
    }

    for(register int x=1; x<DIMENSION-1; x++)
    {
        for(register int y=1; y<DIMENSION-1; y++)
        {
            if(!mirrorCore->if_ban_moves(x,y)) //额外的落子规则限定->Go::is_spec_allowed_move()
            {
                if(mirrorCore->is_allowed_move(x,y))
                {
                    mirrorCore->doit(x,y);
                    ptr_subNodes->push_back(create_Node(mirrorCore->board, cur_Node));

                    mirrorCore->regret();
                }
            }
        }
    }
}

coordinate ABMinMax::find_diff_parent(const Nodes * const cur_Node)
{
    coordinate coo;
    coo.first = 0;
    coo.second = 0;

    int parent_board[DIMENSION][DIMENSION];
    int cur_board[DIMENSION][DIMENSION];
    cur_Node->getBoard(cur_board);
    (cur_Node->getParent())->getBoard(parent_board);

    for(register int x=1; x<DIMENSION-1; x++)
    {
        for(register int y=1; y<DIMENSION-1; y++)
        {
            if(parent_board[x][y]==VOID && cur_board[x][y]!=VOID)
            {
                coo.first = x;
                coo.second = y;
                return coo;
            }
        }
    }

    //Debugg
    //myJudgment->txtBoard_fprintf(parent_board, "err_parent");
    //myJudgment->txtBoard_fprintf(cur_board, "err_cur");
    assert(0); //如果运行到这里说明出错了
    return coo;
}

/*void ABMinMax::find_subNode(const int parent_node[][DIMENSION], int sub_node[][DIMENSION], sub_nodes_t *ptr_subNodes,
                                    const int x, const int y, const int cur_depth)
{
    //计算出子节点落子的旗子颜色
    int color = (cur_depth%2) ? whos_turn*(-1) : whos_turn;

    for(register int i=0; i<DIMENSION; i++)
    {
        for(register int j=0; j<DIMENSION; j++)
        {
            sub_node[i][j] = parent_node[i][j];
        }
    }
    sub_node[x][y] = color;

    //ptr_subNodes->push_back(sub_node);
    ptr_subNodes->clear(); //test need to delete later
}*/

float ABMinMax::get_score(const pair<int,int> temp_pair)
{
    return whos_turn * (temp_pair.first - temp_pair.second);
}

/*void ABMinMax::modify_Path(int cur_depth, const Nodes * const cur_Node)
{
    _path[cur_depth] = cur_Node;
}*/
/** alpha-beta minmax **/
